#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <tchar.h>
#include <map>
#include <list>
#include <string>

#define DLL_IMPORT __declspec(dllimport)
#define DLL_EXPORT __declspec(dllexport)
#define CHARACTER_FILE "Gw2MapsCharacters.txt"
#define CHARNAME_LEN 42
#define DESCRIPTION "\n\t\t\t\t\t\t\tGw2Maps\n\t\t\t\t\t\tCharacter Data\n\t\t\tExample:\tProfession:\tfstCharName,sndCharName,...;\nmapping:\tUnknown:=0, Engineer:=1, Necromancer:=2, Thief:=3, Elementalist:=4, Warrior:=5, Ranger:=6, Mesmer:=7, Guardian:=8\n----------------------------------------------------------------------------------------------------------\n"
#define ENGINEER "Engineer:"
#define NECROMANCER "Necromancer:"
#define THIEF "Thief:"
#define ELEMENTALIST "Elementalist:"
#define WARRIOR "Warrior:"
#define RANGER "Ranger:"
#define MESMER "Mesmer:"
#define GUARDIAN "Guardian:"
#define STD_DIR "\\gw2maps"

enum profession{unknown, engineer, necromancer, thief, elementalist, warrior, ranger, mesmer, guardian};

typedef std::map<std::string, enum profession> myMap;

struct characterComperator{
	bool operator()(std::string fst, std::string snd){
		return fst.compare(snd) < 0 ? true : false;
	}
};


myMap characters;


char* getPath(){
	char path[MAX_PATH];
	memset(path, 0, MAX_PATH);
	GetEnvironmentVariable(TEXT("APPDATA"), path, MAX_PATH);
	strcat_s(path, MAX_PATH, STD_DIR);
	return path;
}


DLL_EXPORT myMap* loadCharacters(){ 
	FILE *in;
	char *name, c;
	int pos;
	enum profession prof;
	auto skipSpaces = [&](){c=fgetc(in); while((c==' ' || c=='\n' || c=='\t' || c=='\r')&& !feof(in))c=fgetc(in);};
	name = (char*)malloc(MAX_PATH);
	sprintf_s(name, MAX_PATH, "%s\\%s", getPath(), CHARACTER_FILE);
	fopen_s(&in, name, "r");
	free(name);
	if(in == 0)
		return 0;
	name = (char*)malloc(CHARNAME_LEN);
	memset(name, '\0', CHARNAME_LEN);
	while(strcmp(name, ENGINEER) != 0){
		memset(name, '\0', CHARNAME_LEN);
		//skipSpaces();
		fscanf_s(in, "%s", name, CHARNAME_LEN);
	}
	prof = engineer;
readName:
	skipSpaces();
	if(c != ';'){
		pos = 0;
		memset(name, '\0', CHARNAME_LEN);
		while(c != ',' && c != ';'){
			name[pos] = c;
			pos++;
			c = fgetc(in);
		}
		characters.emplace(name, prof);
	}
	else 
		free(name);
	if(c == ','){
		name = (char*)malloc(CHARNAME_LEN);
		goto readName;
	}
	else{
		if(!feof(in) && prof != guardian){
			name = (char*)malloc(CHARNAME_LEN);
			fscanf_s(in, "%s", name, CHARNAME_LEN);
			switch(prof){
			case engineer:
				prof = necromancer;
				goto readName;
			case necromancer:
				prof = thief;
				goto readName;
			case thief:
				prof = elementalist;
				goto readName;
			case elementalist:
				prof = warrior;
				goto readName;
			case warrior:
				prof = ranger;
				goto readName;
			case ranger:
				prof = mesmer;
				goto readName;
			case mesmer:
				prof = guardian;
				goto readName;
			case guardian:
				break;
			}
		}
	}
	fclose(in);
	return &characters;
}


DLL_EXPORT void saveCharacters(myMap *characters){
	std::list<std::string> un, en, ne, th, el, wa, ra, me, gu;
	std::list<std::string>::iterator il;
	std::map<std::string, enum profession, characterComperator>::iterator it;
	for(it = characters->begin(); it != characters->end(); it++){
		switch(it->second){
		case unknown: un.push_back(it->first); break;
		case engineer: en.push_back(it->first); break;
		case necromancer: ne.push_back(it->first); break;
		case thief: th.push_back(it->first); break;
		case elementalist: el.push_back(it->first); break;
		case warrior: wa.push_back(it->first); break;
		case ranger: ra.push_back(it->first); break;
		case mesmer: me.push_back(it->first); break;
		case guardian: gu.push_back(it->first); break;
		}
	}
	FILE *out;
	char dir[MAX_PATH];
	sprintf_s(dir, MAX_PATH, "%s\\%s", getPath(), CHARACTER_FILE);
	fopen_s(&out, dir, "w");
	fprintf_s(out, "%s\n", DESCRIPTION);
	fprintf_s(out, "%s\t", ENGINEER);
	for(il = en.begin(); il != en.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", NECROMANCER);
	for(il = ne.begin(); il != ne.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", THIEF);
	for(il = th.begin(); il != th.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", ELEMENTALIST);
	for(il = el.begin(); il != el.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", WARRIOR);
	for(il = wa.begin(); il != wa.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", RANGER);
	for(il = ra.begin(); il != ra.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", MESMER);
	for(il = me.begin(); il != me.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fprintf_s(out, "%s\t", GUARDIAN);
	for(il = gu.begin(); il != gu.end(); il++)
		fprintf_s(out, "%s, ", *il);
	fprintf_s(out, ";\n");
	fclose(out);
}